home *** CD-ROM | disk | FTP | other *** search
- /* X output and frame manipulation routines.
- Copyright (C) 1994, 1995 Board of Trustees, University of Illinois
- Copyright (C) 1994 Lucid, Inc.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Not in FSF. */
-
- /* This file has been Mule-ized, but needs more work before it will
- compile with Mule support enabled. */
-
- /* Author: Chuck Thompson */
-
- #include <config.h>
- #include "lisp.h"
-
- #include "device-x.h"
- #include "frame-x.h"
- #include "EmacsFrame.h"
- #include "EmacsFrameP.h"
- #include "xgccache.h"
- #include "glyphs-x.h"
- #include "objects-x.h"
-
- #include "buffer.h"
- #include "debug.h"
- #include "faces.h"
- #include "redisplay.h"
- #include "sysdep.h"
- #include "window.h"
- #include <X11/bitmaps/gray>
-
- #include "sysproc.h" /* for select() */
-
- /* X_DIVIDER_LINE_WIDTH is the width of the line drawn in the gutter.
- X_DIVIDER_SPACING is the amount of blank space on each side of the line.
- X_DIVIDER_WIDTH = X_DIVIDER_LINE_WIDTH + 2*X_DIVIDER_SPACING
- */
-
- /* Number of pixels below each line. */
- /* #### implement me */
- int x_interline_space;
-
- #define X_DIVIDER_LINE_WIDTH 3
- #define X_DIVIDER_SPACING 2
- #define X_DIVIDER_WIDTH (X_DIVIDER_LINE_WIDTH + 2 * X_DIVIDER_SPACING)
-
- #define EOL_CURSOR_WIDTH 5
-
- /*
- * Prototypes for all functions defined in redisplay-x.c.
- */
- static int x_text_width (struct window *w, Lisp_Object font,
- CONST Emchar *s, Charcount len);
- static void x_font_metric_info (struct device *d, Lisp_Object font,
- struct font_metric_info *fm);
- static int x_divider_width (void);
- static int x_divider_height (void);
- static int x_eol_cursor_width (void);
- static void x_output_end (struct device *d);
- static void x_output_display_block (struct window *w, struct display_line *dl,
- int block, int start, int end,
- int start_pixpos, int cursor_start,
- int cursor_width, int cursor_height);
- static void x_bevel_modeline (struct window *w, struct display_line *dl);
- void x_output_string (struct window *w, struct display_line *dl,
- emchar_dynarr *buf, int xpos, int xoffset,
- int start_pixpos, int width, face_index findex,
- int cursor, int cursor_start, int cursor_width,
- int cursor_height);
- static void x_output_pixmap (struct window *w, struct display_line *dl,
- Lisp_Object image_instance, int xpos,
- int xoffset,
- int start_pixpos, int width, face_index findex,
- int cursor_start, int cursor_width,
- int cursor_height);
- static void x_output_vertical_divider (struct window *w, int clear);
- static void x_output_blank (struct window *w, struct display_line *dl,
- struct rune *rb, int start_pixpos,
- int cursor_start, int cursor_width);
- static void x_output_hline (struct window *w, struct display_line *dl,
- struct rune *rb);
- static void x_clear_to_window_end (struct window *w, int ypos1, int ypos2);
- static void x_redraw_exposed_window (struct window *w, int x, int y,
- int width, int height);
- static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
- int width, int height);
- static void x_clear_region (Lisp_Object window, face_index findex, int x,
- int y, int width, int height);
- static void x_output_eol_cursor (struct window *w, struct display_line *dl,
- int xpos);
- static void x_clear_frame (struct frame *f);
-
- #ifdef MULE
-
- static XFontStruct *
- first_font_struct_of (XFontSet font)
- {
- XFontStruct **font_struct_list;
- char **font_name_list;
- int fonts;
-
- fonts = XFontsOfFontSet (font, &font_struct_list, &font_name_list);
- assert (fonts > 0);
- return font_struct_list[0];
- }
-
- #endif
-
- /*
- * X output and frame manipulation global variables.
- */
-
- /*****************************************************************************
- x_text_width
-
- Given a string and a face, return the string's length in pixels when
- displayed in the font associated with the face.
- ****************************************************************************/
- static int
- x_text_width (struct window *w, Lisp_Object font, CONST Emchar *s,
- Charcount len)
- {
- struct Lisp_Font_Instance *fnt;
-
- fnt = XFONT_INSTANCE (font);
-
- if (!fnt->proportional_p)
- return fnt->width * len;
- else
- {
- #ifdef MULE
- /* !!#### temporary glue */
-
- /* Note: The current glue provided substitutes an X for all
- non-ASCII characters (i.e. >= 0x80). The code is written
- in such a way as to imply that the Xmb*() functions and
- XFontSets should be used to draw text and compute text
- widths. This is not true. Those functions are generally
- losing for a number of reasons:
-
- 1) They only support one locale (e.g. you could display
- Japanese and ASCII text, but not mixed Japanese/Chinese
- text). You could maybe call setlocale() frequently
- to try to deal with this, but that would generally
- fail because an XFontSet is tied to one locale and
- won't have the other character sets in it.
- 2) Not all (or even very many) OS's support the useful
- locales. For example, as far as I know SunOS and
- Solaris only support the Japanese locale if you get the
- special Asian-language version of the OS. Yuck yuck
- yuck. Linux doesn't support the Japanese locale at
- all.
- 3) The locale support in X only exists in R5, not in R4.
- (Not sure how big of a problem this is: how many
- people are using R4?)
- 4) Who knows if the multi-byte text format (which is locale-
- specific) is even the same for the same locale on
- different OS's? It's not even documented anywhere that
- I can find what the multi-byte text format for the
- Japanese locale under SunOS and Solaris is, but I assume
- it's EUC.
-
- In other words, fuck all this losing shit. What we need to do
- instead is provide our own font-set management routines (this
- is what the original Mule does, but of course their implementation
- is shitty). A `font' object under Mule should be allowed to
- have multiple fonts associated with it, just like an XFontSet.
- We can do our own lookup and text-drawing using the *16 functions.
- */
- int i;
- char *one_byte_string = (char *) alloca (len);
- for (i = 0; i < len; i++)
- {
- if (s[i] < 0x80)
- one_byte_string[i] = (char) s[i];
- else
- one_byte_string[i] = 'X';
- }
-
- return XmbTextEscapement (FONT_INSTANCE_X_FONT (fnt),
- one_byte_string, len);
- #else
- int i;
- char *one_byte_string = (char *) alloca (len);
- for (i = 0; i < len; i++)
- {
- /* #### perhaps should use DASSERT? */
- assert (s[i] < 0x100);
- one_byte_string[i] = (char) s[i];
- }
-
- return XTextWidth (FONT_INSTANCE_X_FONT (fnt), one_byte_string, len);
- #endif
- }
- }
-
- /*****************************************************************************
- x_font_metric_info
-
- Given a font, return a structure with its average width, maximum ascent,
- maximum descent and a flag indicating if it is a proportional font.
- ****************************************************************************/
- static void
- x_font_metric_info (struct device *d, Lisp_Object font,
- struct font_metric_info *fm)
- {
- struct Lisp_Font_Instance *fnt = XFONT_INSTANCE (font);
- Lisp_Object dev;
-
- XSETDEVICE (dev, d);
-
- fm->width = fnt->width;
- fm->ascent = fnt->ascent;
- fm->descent = fnt->descent;
- fm->height = fm->ascent + fm->descent;
- fm->proportional = fnt->proportional_p;
- }
-
- /*****************************************************************************
- x_divider_width
-
- Return the width of the vertical divider. This is a function because
- divider_width is a device method.
- ****************************************************************************/
- static int
- x_divider_width (void)
- {
- return X_DIVIDER_WIDTH;
- }
-
- /*****************************************************************************
- x_divider_height
-
- Return the height of the horizontal divider. This is a function because
- divider_height is a device method.
-
- #### If we add etched horizontal divider lines this will have to get
- smarter.
- ****************************************************************************/
- static int
- x_divider_height (void)
- {
- return 1;
- }
-
- /*****************************************************************************
- x_eol_cursor_width
-
- Return the width of the end-of-line cursor. This is a function
- because eol_cursor_width is a device method.
- ****************************************************************************/
- static int
- x_eol_cursor_width (void)
- {
- return EOL_CURSOR_WIDTH;
- }
-
- /*****************************************************************************
- x_output_begin
-
- Perform any necessary initialization prior to an update.
- ****************************************************************************/
- static void
- x_output_begin (struct device *d)
- {
- }
-
- /*****************************************************************************
- x_output_end
-
- Perform any necessary flushing of queues when an update has completed.
- ****************************************************************************/
- static void
- x_output_end (struct device *d)
- {
- XFlush (DEVICE_X_DISPLAY (d));
- }
-
- /*****************************************************************************
- x_output_display_block
-
- Given a display line, a block number for that start line, output all
- runes between start and end in the specified display block.
- ****************************************************************************/
- static void
- x_output_display_block (struct window *w, struct display_line *dl, int block,
- int start, int end, int start_pixpos, int cursor_start,
- int cursor_width, int cursor_height)
- {
- struct frame *f = XFRAME (w->frame);
- emchar_dynarr *buf = Dynarr_new (Emchar);
- Lisp_Object window;
-
- struct display_block *db = Dynarr_atp (dl->display_blocks, block);
- rune_dynarr *rba = db->runes;
- struct rune *rb;
-
- int elt = start;
- face_index findex;
- int xpos, width;
-
- XSETWINDOW (window, w);
- rb = Dynarr_atp (rba, start);
-
- if (!rb)
- {
- /* Nothing to do so don't do anything. */
- return;
- }
- else
- {
- findex = rb->findex;
- xpos = rb->xpos;
- width = 0;
- }
-
- if (end < 0)
- end = Dynarr_length (rba);
- Dynarr_reset (buf);
-
- while (elt < end)
- {
- rb = Dynarr_atp (rba, elt);
-
- if (rb->findex == findex && rb->type == CHAR
- && rb->object.ch != '\n' && rb->cursor_type != CURSOR_ON)
- {
- Dynarr_add (buf, rb->object.ch);
- width += rb->width;
- elt++;
- }
- else
- {
- if (Dynarr_length (buf))
- {
- x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
- findex, 0, cursor_start, cursor_width,
- cursor_height);
- xpos = rb->xpos;
- width = 0;
- }
- Dynarr_reset (buf);
- width = 0;
-
- if (rb->type == CHAR)
- {
- findex = rb->findex;
- xpos = rb->xpos;
-
- if (rb->cursor_type == CURSOR_ON)
- {
- if (rb->object.ch == '\n')
- {
- x_output_eol_cursor (w, dl, xpos);
- }
- else
- {
- Dynarr_add (buf, rb->object.ch);
- x_output_string (w, dl, buf, xpos, 0, start_pixpos,
- rb->width, findex, 1, cursor_start,
- cursor_width, cursor_height);
- Dynarr_reset (buf);
- }
-
- xpos += rb->width;
- elt++;
- }
- else if (rb->object.ch == '\n')
- {
- /* Clear in case a cursor was formerly here. */
- int height = dl->ascent + dl->descent - dl->clip;
-
- x_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
- rb->width, height);
- elt++;
- }
- }
- else if (rb->type == BLANK || rb->type == HLINE)
- {
- if (rb->type == BLANK)
- x_output_blank (w, dl, rb, start_pixpos, cursor_start,
- cursor_width);
- else
- {
- /* #### Our flagging of when we need to redraw the
- modeline shadows sucks. Since HLINE is only used
- by the modeline at the moment it is a good bet
- that if it gets redrawn then we should also
- redraw the shadows. This won't be true forever.
- We borrow the shadow_thickness_changed flag for
- now. */
- w->shadow_thickness_changed = 1;
- x_output_hline (w, dl, rb);
- }
-
- elt++;
- if (elt < end)
- {
- rb = Dynarr_atp (rba, elt);
-
- findex = rb->findex;
- xpos = rb->xpos;
- }
- }
- else if (rb->type == DGLYPH)
- {
- Lisp_Object instance;
-
- XSETWINDOW (window, w);
- instance = glyph_image_instance (rb->object.dglyph.glyph,
- window, 1);
- findex = rb->findex;
-
- switch (XIMAGE_INSTANCE_TYPE (instance))
- {
- case IMAGE_TEXT:
- {
- /* #### This is way losing. See the comment in
- add_glyph_rune(). */
- #ifdef MULE
- /* lose; */
- /* !!#### Chuck, you need to lower this stuff
- to the device-independent level. */
- Dynarr_add (buf, 'l');
- Dynarr_add (buf, 'o');
- Dynarr_add (buf, 's');
- Dynarr_add (buf, 'e');
- #else
- Bytecount lossage;
- Lisp_Object string =
- XIMAGE_INSTANCE_TEXT_STRING (instance);
-
- for (lossage = 0;
- lossage < string_length (XSTRING (string));
- lossage++)
- Dynarr_add (buf,
- (Emchar) string_byte (XSTRING (string),
- lossage));
-
- x_output_string (w, dl, buf, xpos,
- rb->object.dglyph.xoffset,
- start_pixpos, -1, findex,
- (rb->cursor_type == CURSOR_ON),
- cursor_start, cursor_width,
- cursor_height);
- Dynarr_reset (buf);
- #endif
- }
- break;
-
- case IMAGE_MONO_PIXMAP:
- case IMAGE_COLOR_PIXMAP:
- x_output_pixmap (w, dl, instance, xpos,
- rb->object.dglyph.xoffset, start_pixpos,
- rb->width, findex, cursor_start,
- cursor_width, cursor_height);
- break;
-
- case IMAGE_CURSOR:
- abort ();
-
- case IMAGE_SUBWINDOW:
- /* #### implement me */
- break;
-
- case IMAGE_NOTHING:
- /* nothing is as nothing does */
- break;
-
- default:
- abort ();
- }
-
- xpos += rb->width;
- elt++;
- }
- else
- abort ();
- }
- }
-
- if (Dynarr_length (buf))
- x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex, 0,
- cursor_start, cursor_width, cursor_height);
-
- /* #### This is really conditionalized well for optimized
- performance. */
- if (dl->modeline
- && !EQ (Qzero, w->modeline_shadow_thickness)
- && (f->clear
- || f->windows_structure_changed
- || w->shadow_thickness_changed))
- x_bevel_modeline (w, dl);
-
- Dynarr_free (buf);
- }
-
- /*****************************************************************************
- x_bevel_modeline
-
- Draw a 3d border around the modeline on window W.
- ****************************************************************************/
- static void
- x_bevel_modeline (struct window *w, struct display_line *dl)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
- EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
- GC top_shadow_gc, bottom_shadow_gc, background_gc;
- Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
- XColor tmp_color;
- Lisp_Object tmp_pixel;
- int x, y, width, height;
- XGCValues gcv;
- unsigned long mask;
- int use_pixmap = 0;
- int flip_gcs = 0;
- int shadow_thickness;
-
- memset (&gcv, ~0, sizeof (XGCValues));
-
- tmp_pixel = FACE_CACHE_ELEMENT_BACKGROUND (w, MODELINE_INDEX);
- tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
-
- /* First, get the GC's. */
- top_shadow_pixel = tmp_color.pixel;
- bottom_shadow_pixel = tmp_color.pixel;
- background_pixel = tmp_color.pixel;
-
- x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
- background_pixel, ef->core.background_pixel);
-
- tmp_pixel = FACE_CACHE_ELEMENT_FOREGROUND (w, MODELINE_INDEX);
- tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
- gcv.background = tmp_color.pixel;
- gcv.graphics_exposures = False;
- mask = GCForeground | GCBackground | GCGraphicsExposures;
-
- if (top_shadow_pixel == background_pixel ||
- bottom_shadow_pixel == background_pixel)
- use_pixmap = 1;
-
- if (use_pixmap)
- {
- if (DEVICE_X_GRAY_PIXMAP (d) == None)
- {
- DEVICE_X_GRAY_PIXMAP (d) =
- XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
- gray_width, gray_height, 1, 0, 1);
- }
-
- tmp_pixel = FACE_CACHE_ELEMENT_BACKGROUND (w, MODELINE_INDEX);
- tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
- gcv.foreground = tmp_color.pixel;
- gcv.fill_style = FillOpaqueStippled;
- gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
- top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
- (mask | GCStipple | GCFillStyle));
-
- tmp_pixel = FACE_CACHE_ELEMENT_FOREGROUND (w, MODELINE_INDEX);
- tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
- bottom_shadow_pixel = tmp_color.pixel;
-
- flip_gcs = (bottom_shadow_pixel ==
- WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
- }
- else
- {
- gcv.foreground = top_shadow_pixel;
- top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
- }
-
- gcv.foreground = bottom_shadow_pixel;
- bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
-
- if (use_pixmap && flip_gcs)
- {
- GC tmp_gc = bottom_shadow_gc;
- bottom_shadow_gc = top_shadow_gc;
- top_shadow_gc = tmp_gc;
- }
-
- gcv.foreground = background_pixel;
- background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
-
- if (XINT (w->modeline_shadow_thickness) < 0)
- {
- GC temp;
-
- temp = top_shadow_gc;
- top_shadow_gc = bottom_shadow_gc;
- bottom_shadow_gc = temp;
- }
-
- shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
-
- x = WINDOW_MODELINE_LEFT (w);
- width = WINDOW_MODELINE_RIGHT (w) - x;
- y = dl->ypos - dl->ascent - shadow_thickness;
- height = dl->ascent + dl->descent + 2 * shadow_thickness;
-
- x_output_shadows (f, x, y, width, height, top_shadow_gc, bottom_shadow_gc,
- background_gc, shadow_thickness);
- }
-
- /*****************************************************************************
- x_get_gc
-
- Given a number of parameters return a GC with those properties.
- ****************************************************************************/
- static GC
- x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
- Lisp_Object bg_pmap, Lisp_Object lwidth)
- {
- XGCValues gcv;
- unsigned long mask;
-
- memset (&gcv, ~0, sizeof (XGCValues));
- gcv.graphics_exposures = False;
- /* Make absolutely sure that we don't pick up a clipping region in
- the GC returned by this function. */
- gcv.clip_mask = None;
- gcv.clip_x_origin = 0;
- gcv.clip_y_origin = 0;
- gcv.fill_style = FillSolid;
- mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
- mask |= GCFillStyle;
-
- if (!NILP (font))
- {
- gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
- mask |= GCFont;
- }
-
- if (!NILP (fg))
- {
- if (COLOR_INSTANCEP (fg))
- gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
- else
- gcv.foreground = XINT (fg);
- mask |= GCForeground;
- }
-
- if (!NILP (bg))
- {
- if (COLOR_INSTANCEP (bg))
- gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
- else
- gcv.background = XINT (bg);
- mask |= GCBackground;
- }
-
- if (IMAGE_INSTANCEP (bg_pmap)
- && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
- {
- if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
- {
- gcv.fill_style = FillOpaqueStippled;
- gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
- mask |= (GCStipple | GCFillStyle);
- }
- else
- {
- gcv.fill_style = FillTiled;
- gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
- mask |= (GCTile | GCFillStyle);
- }
- }
-
- if (!NILP (lwidth))
- {
- gcv.line_width = XINT (lwidth);
- mask |= GCLineWidth;
- }
-
- return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
- }
-
- /*****************************************************************************
- x_output_string
-
- Given a string and a starting position, output that string in the
- given face. If cursor is true, draw a cursor around the string.
- ****************************************************************************/
- void
- x_output_string (struct window *w, struct display_line *dl,
- emchar_dynarr *buf, int xpos, int xoffset, int start_pixpos,
- int width, face_index findex, int cursor, int cursor_start,
- int cursor_width, int cursor_height)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- Lisp_Object device = Qnil;
- Lisp_Object window = Qnil;
- Lisp_Object font, bg_pmap;
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
- GC bgc, gc;
- Pixel cursor_color;
- int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS (d));
- int cursor_clip;
-
- struct font_metric_info fm;
- int height, font_height, clip_x, clip_width;
-
- XSETDEVICE (device, d);
- XSETWINDOW (window, w);
-
- font = FACE_CACHE_ELEMENT_FONT (w, findex);
- x_font_metric_info (d, font, &fm);
- font_height = fm.ascent + fm.descent;
-
- bg_pmap = FACE_CACHE_ELEMENT_BACKGROUND_PIXMAP (w, findex);
- if (!IMAGE_INSTANCEP (bg_pmap)
- || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
- bg_pmap = Qnil;
-
- if (width < 0)
- width = x_text_width (w, font, Dynarr_atp (buf, 0), Dynarr_length (buf));
- height = dl->ascent + dl->descent - dl->clip;
-
- cursor_clip = (cursor_start >= max (xpos, start_pixpos) &&
- cursor_start < (xpos + width));
-
- if (cursor
- || cursor_clip
- || (cursor_width
- && (cursor_start + cursor_width >= xpos)
- && !NILP (Vbar_cursor)))
- {
- XtVaGetValues (FRAME_X_TEXT_WIDGET (f), XtNcursorColor,
- &cursor_color, 0);
- }
-
- /* Adjust for any possible clipping of the left side. */
- if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
- {
- if (start_pixpos > xpos && start_pixpos > xpos + width)
- return;
-
- clip_x = xoffset;
- clip_width = width;
-
- if (start_pixpos > xpos)
- {
- clip_x += (start_pixpos - xpos);
- clip_width -= (start_pixpos - xpos);
- }
- }
- else
- {
- clip_x = 0;
- clip_width = width;
- }
-
- if (cursor && focus && NILP (Vbar_cursor))
- {
- gc = x_get_gc (d, font, FACE_CACHE_ELEMENT_BACKGROUND (w, findex),
- make_number (cursor_color), Qnil, Qnil);
- bgc = 0;
- }
- else
- {
- gc = x_get_gc (d, font, FACE_CACHE_ELEMENT_FOREGROUND (w, findex),
- FACE_CACHE_ELEMENT_BACKGROUND (w, findex), Qnil, Qnil);
- bgc = x_get_gc (d, font, FACE_CACHE_ELEMENT_FOREGROUND (w, findex),
- FACE_CACHE_ELEMENT_BACKGROUND (w, findex),
- bg_pmap, Qnil);
- }
-
- if (dl->clip || clip_x)
- {
- XRectangle clip_box[1];
-
- clip_box[0].x = clip_x;
- clip_box[0].y = 0;
- clip_box[0].width = clip_width;
- clip_box[0].height = height;
-
- XSetClipRectangles (dpy, gc, xpos - xoffset, dl->ypos - dl->ascent,
- clip_box, 1, Unsorted);
- }
-
- /* XDrawImageString only clears the area equal to the height of
- the given font. It is possible that a font is being displayed
- on a line taller than it is, so this would cause us to fail to
- clear some areas. */
- if (font_height < (int) (height + dl->clip))
- {
- if (cursor)
- {
- int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
-
- ypos1_string = dl->ypos - fm.ascent;
- ypos2_string = dl->ypos + fm.descent;
- ypos1_line = dl->ypos - dl->ascent;
- ypos2_line = dl->ypos + dl->descent - dl->clip;
-
- /* Make sure we don't clear below the real bottom of the
- line. */
- if (ypos1_string > ypos2_line)
- ypos1_string = ypos2_line;
- if (ypos2_string > ypos2_line)
- ypos2_string = ypos2_line;
-
- if (ypos1_line < ypos1_string)
- {
- x_clear_region (window, findex, xpos + clip_x, ypos1_line,
- clip_width, ypos1_string - ypos1_line);
- }
-
- if (ypos2_line > ypos2_string)
- {
- x_clear_region (window, findex, xpos + clip_x, ypos2_string,
- clip_width, ypos2_line - ypos2_string);
- }
- }
- else
- {
- x_clear_region (window, findex, xpos + clip_x,
- dl->ypos - dl->ascent, clip_width, height);
- }
- }
-
- #ifdef MULE
- {
- /* !!#### temporary glue */
- int i;
- Emchar *s = Dynarr_atp (buf, 0);
- int len = Dynarr_length (buf);
- char *one_byte_string = (char *) alloca (len);
- for (i = 0; i < len; i++)
- {
- if (s[i] < 0x80)
- one_byte_string[i] = (char) s[i];
- else
- one_byte_string[i] = 'X';
- }
-
- XmbDrawImageString (dpy, x_win, FONT_INSTANCE_X_FONT (font), gc, xpos,
- dl->ypos, one_byte_string, len);
- }
- #else
- {
- int i;
- Emchar *s = Dynarr_atp (buf, 0);
- int len = Dynarr_length (buf);
- char *one_byte_string = (char *) alloca (len);
- for (i = 0; i < len; i++)
- {
- /* #### perhaps should use DASSERT? */
- assert (s[i] < 0x100);
- one_byte_string[i] = (char) s[i];
- }
-
- if (!NILP (bg_pmap) && bgc)
- {
- XFillRectangle (dpy, x_win, bgc, xpos + clip_x, dl->ypos - dl->ascent,
- clip_width, height);
- XDrawString (dpy, x_win, gc, xpos - xoffset, dl->ypos,
- one_byte_string, len);
- }
- else
- XDrawImageString (dpy, x_win, gc, xpos - xoffset, dl->ypos,
- one_byte_string, len);
- }
- #endif
-
- /* We draw underlines in the same color as the text. */
- if (FACE_CACHE_ELEMENT_UNDERLINE_P (w, findex))
- {
- unsigned long upos, uthick;
- XFontStruct *xfont;
-
- #ifdef MULE
- xfont =
- first_font_struct_of (FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)));
- #else
- xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
- #endif
- if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
- upos = 0;
- if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
- uthick = 1;
-
- if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
- {
- if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
- uthick = dl->descent - dl->clip - upos;
-
- if (uthick == 1)
- {
- XDrawLine (dpy, x_win, gc, xpos + clip_x, dl->ypos + upos,
- xpos + clip_x + clip_width, dl->ypos + upos);
- }
- else if (uthick > 1)
- {
- XFillRectangle (dpy, x_win, gc, xpos + clip_x, dl->ypos + upos,
- clip_width, uthick);
- }
- }
- }
-
- /* Restore the GC */
- if (dl->clip || clip_x)
- {
- XSetClipMask (dpy, gc, None);
- XSetClipOrigin (dpy, gc, 0, 0);
- }
-
- /* If we are actually superimposing the cursor then redraw with just
- the appropriate section highlighted. */
- if (cursor_clip && !cursor && focus)
- {
- GC cgc;
- XRectangle clip_box[1];
-
- cgc = x_get_gc (d, font, FACE_CACHE_ELEMENT_BACKGROUND (w, findex),
- make_number (cursor_color), Qnil, Qnil);
-
- clip_box[0].x = cursor_start - start_pixpos;
- clip_box[0].y = 0;
- clip_box[0].width =
- min (cursor_width, (start_pixpos + width - cursor_start));
- clip_box[0].height = height;
-
- XSetClipRectangles (dpy, cgc, cursor_start, dl->ypos - dl->ascent,
- clip_box, 1, Unsorted);
- #ifdef MULE
- no way jose
- #else
- {
- /* #### Should reuse the string we create above. */
- int i;
- Emchar *s = Dynarr_atp (buf, 0);
- int len = Dynarr_length (buf);
- char *one_byte_string = (char *) alloca (len);
- for (i = 0; i < len; i++)
- {
- /* #### perhaps should use DASSERT? */
- assert (s[i] < 0x100);
- one_byte_string[i] = (char) s[i];
- }
-
- XDrawImageString (dpy, x_win, cgc, cursor_start, dl->ypos,
- one_byte_string, len);
- }
- #endif
-
- XSetClipMask (dpy, cgc, None);
- XSetClipOrigin (dpy, cgc, 0, 0);
- }
-
- /* Draw the non-focus box or bar-cursor as needed. */
- if ((cursor && !focus && NILP (Vbar_cursor))
- || (cursor_width
- && (cursor_start + cursor_width >= xpos)
- && !NILP (Vbar_cursor)))
- {
- int tmp_height, tmp_y;
- int bar_width = EQ (Vbar_cursor, Qt) ? 1 : 2;
- int cursor_x;
-
- if (!NILP (Vbar_cursor))
- {
- gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil,
- make_number (bar_width));
- }
- else
- {
- gc = x_get_gc (d, Qnil, make_number (cursor_color),
- Qnil, Qnil, Qnil);
- }
-
- if (cursor)
- cursor_x = xpos;
- else
- cursor_x = cursor_start;
-
- tmp_y = dl->ypos - fm.ascent;
- tmp_height = cursor_height;
- if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height))
- {
- tmp_y = dl->ypos - dl->ascent + height - tmp_height;
- if (tmp_y < (int) (dl->ypos - dl->ascent))
- tmp_y = dl->ypos - dl->ascent;
- tmp_height = dl->ypos - dl->ascent + height - tmp_y;
- }
-
- if (!focus && NILP (Vbar_cursor))
- {
- XDrawRectangle (dpy, x_win, gc, cursor_x, tmp_y, cursor_width - 1,
- tmp_height - 1);
- }
- else if (focus && !NILP (Vbar_cursor))
- {
- XDrawLine (dpy, x_win, gc, cursor_x + bar_width - 1, tmp_y,
- cursor_x + bar_width - 1, tmp_y + tmp_height - 1);
- }
- }
- }
-
- void
- x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
- int y, int clip_x, int clip_y, int clip_width,
- int clip_height, int width, int height, int pixmap_offset,
- unsigned long fg, unsigned long bg, GC override_gc)
- {
- struct device *d = XDEVICE (f->device);
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
-
- GC gc;
- XGCValues gcv;
- unsigned long pixmap_mask;
-
- if (!override_gc)
- {
- memset (&gcv, ~0, sizeof (XGCValues));
- gcv.graphics_exposures = False;
- gcv.foreground = fg;
- gcv.background = bg;
- pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
-
- if (IMAGE_INSTANCE_X_MASK (p))
- {
- gcv.function = GXcopy;
- gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
- gcv.clip_x_origin = x;
- gcv.clip_y_origin = y - pixmap_offset;
- pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
- GCClipYOrigin);
- }
-
- gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
- }
- else
- gc = override_gc;
-
- if (clip_x || clip_y)
- {
- XRectangle clip_box[1];
-
- clip_box[0].x = clip_x;
- clip_box[0].y = clip_y;
- clip_box[0].width = clip_width;
- clip_box[0].height = clip_height;
-
- XSetClipRectangles (dpy, gc, x, y, clip_box, 1, Unsorted);
- }
-
- /* depth of 0 means it's a bitmap, not a pixmap, and we should use
- XCopyPlane (1 = current foreground color, 0 = background) instead
- of XCopyArea, which means that the bits in the pixmap are actual
- pixel values, instead of symbolic of fg/bg. */
- if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
- {
- XCopyArea (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
- pixmap_offset, width,
- height, x, y);
- }
- else
- {
- XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
- (pixmap_offset < 0
- ? 0
- : pixmap_offset),
- width, height, x,
- (pixmap_offset < 0
- ? y - pixmap_offset
- : y),
- 1L);
- }
-
- if (clip_x || clip_y)
- {
- XSetClipMask (dpy, gc, None);
- XSetClipOrigin (dpy, gc, 0, 0);
- }
- }
-
- static void
- x_output_pixmap (struct window *w, struct display_line *dl,
- Lisp_Object image_instance, int xpos, int xoffset,
- int start_pixpos, int width, face_index findex,
- int cursor_start, int cursor_width, int cursor_height)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
- struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
- Lisp_Object window;
-
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
- int lheight = dl->ascent + dl->descent - dl->clip;
- int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
- IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
- int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p));
- int clip_x, clip_y, clip_width, clip_height;
-
- /* The pixmap_offset is used to center the pixmap on lines which are
- shorter than it is. This results in odd effects when scrolling
- pixmaps off of the bottom. Let's try not using it. */
- #if 0
- int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
- #else
- int pixmap_offset = 0;
- #endif
-
- XSETWINDOW (window, w);
-
- if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
- {
- if (start_pixpos > xpos && start_pixpos > xpos + width)
- return;
-
- clip_x = xoffset;
- clip_width = width;
- if (start_pixpos > xpos)
- {
- clip_x += (start_pixpos - xpos);
- clip_width -= (start_pixpos - xpos);
- }
- }
- else
- {
- clip_x = 0;
- clip_width = 0;
- }
-
- /* Place markers for possible future functionality (clipping the top
- half instead of the bottom half; think pixel scrolling). */
- clip_y = 0;
- clip_height = pheight;
-
- /* Clear the area the pixmap is going into. The pixmap itself will
- always take care of the full width. We don't want to clear where
- it is going to go in order to avoid flicker. So, all we have to
- take care of is any area above or below the pixmap. */
- /* #### We take a shortcut for now. We know that since we have
- pixmap_offset hardwired to 0 that the pixmap is against the top
- edge so all we have to worry about is below it. */
- /* #### Unless the pixmap has a mask in which case we have to clear
- the whole damn thing since we can't yet clear just the area not
- included in the mask. */
- if (((int) (dl->ypos - dl->ascent + pheight) <
- (int) (dl->ypos + dl->descent - dl->clip))
- || IMAGE_INSTANCE_X_MASK (p))
- {
- int clear_x, clear_y, clear_width, clear_height;
-
- if (IMAGE_INSTANCE_X_MASK (p))
- {
- clear_y = dl->ypos - dl->ascent;
- clear_height = lheight;
- }
- else
- {
- clear_y = dl->ypos - dl->ascent + pheight;
- clear_height = lheight - pheight;
- }
-
- if (start_pixpos >= 0 && start_pixpos > xpos)
- {
- clear_x = start_pixpos;
- clear_width = xpos + width - start_pixpos;
- }
- else
- {
- clear_x = xpos;
- clear_width = width;
- }
-
- x_clear_region (window, findex, clear_x, clear_y,
- clear_width, clear_height);
- }
-
- /* Output the pixmap. */
- {
- Lisp_Object tmp_pixel;
- XColor tmp_bcolor, tmp_fcolor;
-
- tmp_pixel = FACE_CACHE_ELEMENT_FOREGROUND (w, findex);
- tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
- tmp_pixel = FACE_CACHE_ELEMENT_BACKGROUND (w, findex);
- tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
-
- x_output_x_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x,
- clip_y, clip_width, clip_height,
- pwidth, pheight, pixmap_offset,
- tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
- }
-
- /* Draw a cursor over top of the pixmap. */
- if (cursor_width && cursor_height && (cursor_start >= xpos)
- && (cursor_start < xpos + pwidth))
- {
- Pixel cursor_color;
- GC gc;
- int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS (d));
- int y = dl->ypos - dl->ascent;
-
-
- XtVaGetValues (FRAME_X_TEXT_WIDGET (f), XtNcursorColor,
- &cursor_color, 0);
- gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil, Qnil);
-
- if (cursor_width > xpos + pwidth - cursor_start)
- cursor_width = xpos + pwidth - cursor_start;
-
- if (focus)
- {
- XFillRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
- cursor_height);
- }
- else
- {
- XDrawRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
- cursor_height);
- }
- }
- }
-
- /*****************************************************************************
- x_output_vertical_divider
-
- Draw a vertical divider down the left side of the given window.
- ****************************************************************************/
- static void
- x_output_vertical_divider (struct window *w, int clear)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
-
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
- GC gc;
-
- /* We don't use the normal gutter measurements here because the
- horizontal scrollbars and toolbars do not stretch completely over
- to the right edge of the window. Only the modeline does. */
- int modeline_height = window_modeline_height (w);
- int x1, x2;
- int y1, y2;
-
- if (f->scrollbar_on_left)
- x1 = WINDOW_LEFT (w);
- else
- x1 = WINDOW_RIGHT (w) - X_DIVIDER_WIDTH;
- x2 = x1 + X_DIVIDER_SPACING;
-
- if (f->scrollbar_on_top)
- y1 = WINDOW_TOP (w);
- else
- y1 = WINDOW_TEXT_TOP (w);
- y2 = WINDOW_BOTTOM (w) - modeline_height;
-
- /* Draw the divider in the window. */
- {
- /* Clear the divider area first. This needs to be done when a
- window split occurs. */
- if (clear)
- XClearArea (dpy, x_win, x1, y1, X_DIVIDER_WIDTH, y2 - y1, False);
-
- /* #### There needs to be some checks to make sure that whatever
- colors we choose, the line will be visible (not same color as
- default background. */
- gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_BACKGROUND (w, MODELINE_INDEX),
- FACE_CACHE_ELEMENT_FOREGROUND (w, MODELINE_INDEX),
- Qnil, Qnil);
-
- /* Draw the divider line. */
- XFillRectangle (dpy, x_win, gc, x2, y1, X_DIVIDER_LINE_WIDTH, y2 - y1);
- }
-
- /* Draw the divider in the modeline but only if we are using 2D
- modelines. */
- if (EQ (Qzero, w->modeline_shadow_thickness))
- {
- XFillRectangle (dpy, x_win, gc, x1, y2, X_DIVIDER_WIDTH,
- modeline_height);
-
- /* #### There needs to be some checks to make sure that whatever
- colors we choose, the line will be visible (not same color as
- default background. */
- gc = x_get_gc (d, Qnil,
- FACE_CACHE_ELEMENT_FOREGROUND (w, MODELINE_INDEX),
- FACE_CACHE_ELEMENT_BACKGROUND (w, MODELINE_INDEX),
- Qnil, Qnil);
-
- /* Draw the divider line. */
- XFillRectangle (dpy, x_win, gc, x2, y2, X_DIVIDER_LINE_WIDTH,
- modeline_height);
- }
- }
-
- /*****************************************************************************
- x_output_blank
-
- Output a blank by clearing the area it covers in the foreground color
- of its face.
- ****************************************************************************/
- static void
- x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
- int start_pixpos, int cursor_start, int cursor_width)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
-
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
- GC gc;
- Pixel cursor_color;
- Lisp_Object bg_pmap;
-
- int x = rb->xpos;
- int y = dl->ypos - dl->ascent;
- int width = rb->width;
- int height = dl->ascent + dl->descent - dl->clip;
-
- if (start_pixpos > x)
- {
- if (start_pixpos >= (x + width))
- return;
- else
- {
- width -= (start_pixpos - x);
- x = start_pixpos;
- }
- }
-
- bg_pmap = FACE_CACHE_ELEMENT_BACKGROUND_PIXMAP (w, rb->findex);
- if (!IMAGE_INSTANCEP (bg_pmap)
- || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
- bg_pmap = Qnil;
-
- if (NILP (bg_pmap))
- gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_BACKGROUND (w, rb->findex),
- Qnil, Qnil, Qnil);
- else
- gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_FOREGROUND (w, rb->findex),
- FACE_CACHE_ELEMENT_BACKGROUND (w, rb->findex), bg_pmap,
- Qnil);
-
- XFillRectangle (dpy, x_win, gc, x, y, width, height);
-
- /* If this rune is marked as having the cursor, then it is actually
- representing a tab. */
- if (rb->cursor_type == CURSOR_ON
- || (cursor_width
- && (cursor_start + cursor_width > x)
- && cursor_start < (x + width)))
- {
- struct font_metric_info fm;
- int cursor_height, cursor_y;
- int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS (d));
-
- XtVaGetValues (FRAME_X_TEXT_WIDGET (f), XtNcursorColor,
- &cursor_color, 0);
- gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil, Qnil);
-
- x_font_metric_info (d, FACE_CACHE_ELEMENT_FONT (w, rb->findex), &fm);
-
- cursor_y = dl->ypos - fm.ascent;
- cursor_height = fm.height;
- if (cursor_y + cursor_height > y + height)
- cursor_height = y + height - cursor_y;
-
- if (focus)
- {
- if (NILP (Vbar_cursor))
- {
- XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y, fm.width,
- cursor_height);
- }
- else
- {
- int bar_width = EQ (Vbar_cursor, Qt) ? 1 : 2;
-
- gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil,
- make_number (bar_width));
- XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
- cursor_y, cursor_start + bar_width - 1,
- cursor_y + cursor_height - 1);
- }
- }
- else if (NILP (Vbar_cursor))
- {
- XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y, fm.width - 1,
- cursor_height - 1);
- }
- }
- }
-
- /*****************************************************************************
- x_output_hline
-
- Output a horizontal line in the foreground of its face.
- ****************************************************************************/
- static void
- x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
-
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
- GC gc;
-
- int x = rb->xpos;
- int width = rb->width;
- int height = dl->ascent + dl->descent - dl->clip;
- int ypos1, ypos2, ypos3, ypos4;
-
- ypos1 = dl->ypos - dl->ascent;
- ypos2 = ypos1 + rb->object.hline.yoffset;
- ypos3 = ypos2 + rb->object.hline.thickness;
- ypos4 = dl->ypos + dl->descent - dl->clip;
-
- /* First clear the area not covered by the line. */
- if (height - rb->object.hline.thickness > 0)
- {
- gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_FOREGROUND (w, rb->findex),
- Qnil, Qnil, Qnil);
-
- if (ypos2 - ypos1 > 0)
- XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
- if (ypos4 - ypos3 > 0)
- XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
- }
-
- /* Now draw the line. */
- gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_BACKGROUND (w, rb->findex),
- Qnil, Qnil, Qnil);
-
- if (ypos2 < ypos1)
- ypos2 = ypos1;
- if (ypos3 > ypos4)
- ypos3 = ypos4;
-
- if (ypos3 - ypos2 > 0)
- XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
- }
-
- /*****************************************************************************
- x_output_shadows
-
- Draw a shadow around the given area using the given GC's. It is the
- callers responsibility to ste the GC's appropriately.
- ****************************************************************************/
- void
- x_output_shadows (struct frame *f, int x, int y, int width, int height,
- GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
- int shadow_thickness)
- {
- struct device *d = XDEVICE (f->device);
-
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
-
- XSegment top_shadow[20], bottom_shadow[20];
- int elt;
-
- if (shadow_thickness > 10)
- shadow_thickness = 10;
- else if (shadow_thickness < 0)
- shadow_thickness = 0;
- if (shadow_thickness > (width / 2))
- shadow_thickness = width / 2;
- if (shadow_thickness > (height / 2))
- shadow_thickness = height / 2;
-
- for (elt = 0; elt < shadow_thickness; elt++)
- {
- int seg1 = elt;
- int seg2 = elt + shadow_thickness;
-
- top_shadow[seg1].x1 = x;
- top_shadow[seg1].x2 = x + width - elt - 1;
- top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
-
- top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
- top_shadow[seg2].y1 = y + shadow_thickness;
- top_shadow[seg2].y2 = y + height - elt - 1;
-
- bottom_shadow[seg1].x1 = x + elt + 1;
- bottom_shadow[seg1].x2 = x + width - 1;
- bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
-
- bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
- bottom_shadow[seg2].y1 = y + elt + 1;
- bottom_shadow[seg2].y2 = y + height - shadow_thickness;
- }
-
- XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
- XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
- shadow_thickness * 2);
- }
-
- /*****************************************************************************
- x_generate_shadow_pixels
-
- Given three pixels (top shadow, bottom shadow, background) massage
- the top and bottom shadow colors to guarantee that they differ. The
- background pixels are not allowed to be modified.
-
- This function modifies its parameters.
-
- This code is modified from code blatantly stolen from lwlib/xlwmenu.c
- ****************************************************************************/
- #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
- ? ((unsigned long) (x)) : ((unsigned long) (y)))
-
- void
- x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
- unsigned long *bottom_shadow,
- unsigned long background,
- unsigned long core_background)
- {
- struct device *d = XDEVICE (f->device);
- Display *dpy = DEVICE_X_DISPLAY (d);
- Colormap cmap =
- DefaultColormapOfScreen (XtScreen ((Widget) FRAME_X_TEXT_WIDGET (f)));
-
- XColor topc, botc;
- int top_frobbed = 0, bottom_frobbed = 0;
-
- /* If the top shadow is the same color as the background, try and
- adjust it. */
- if (*top_shadow == background)
- {
- topc.pixel = background;
- XQueryColor (dpy, cmap, &topc);
- /* don't overflow/wrap! */
- topc.red = MINL (65535, topc.red * 1.2);
- topc.green = MINL (65535, topc.green * 1.2);
- topc.blue = MINL (65535, topc.blue * 1.2);
- if (allocate_nearest_color (dpy, cmap, &topc))
- {
- *top_shadow = topc.pixel;
- top_frobbed = 1;
- }
- }
-
- /* If the bottom shadow is the same color as the background, try and
- adjust it. */
- if (*bottom_shadow == background)
- {
- botc.pixel = background;
- XQueryColor (dpy, cmap, &botc);
- botc.red *= 0.6;
- botc.green *= 0.6;
- botc.blue *= 0.6;
- if (allocate_nearest_color (dpy, cmap, &botc))
- {
- *bottom_shadow = botc.pixel;
- bottom_frobbed = 1;
- }
- }
-
- /* If we had to adjust both shadows, then we have to do some
- additional work. */
- if (top_frobbed && bottom_frobbed)
- {
- int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
- int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
- if (bot_avg > top_avg)
- {
- Pixel tmp = *top_shadow;
-
- *top_shadow = *bottom_shadow;
- *bottom_shadow = tmp;
- }
- else if (topc.pixel == botc.pixel)
- {
- if (botc.pixel == background)
- *top_shadow = core_background;
- else
- *bottom_shadow = background;
- }
- }
- }
-
- /*****************************************************************************
- x_clear_to_window_end
-
- Clear the area between ypos1 and ypos2. Each margin area and the
- text area is handled separately since they may each have their own
- background color.
- ****************************************************************************/
- static void
- x_clear_to_window_end (struct window *w, int ypos1, int ypos2)
- {
- int height = ypos2 - ypos1;
-
- if (height)
- {
- struct frame *f = XFRAME (w->frame);
- Lisp_Object window;
- int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
- layout_bounds bounds;
-
- bounds = calculate_display_line_boundaries (w, bflag);
- XSETWINDOW (window, w);
-
- if (window_is_leftmost (w))
- x_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
- ypos1, FRAME_BORDER_WIDTH (f), height);
-
- if (bounds.left_in - bounds.left_out > 0)
- x_clear_region (window,
- get_builtin_face_cache_index (w, Vleft_margin_face),
- bounds.left_out, ypos1,
- bounds.left_in - bounds.left_out, height);
-
- if (bounds.right_in - bounds.left_in > 0)
- x_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
- bounds.right_in - bounds.left_in, height);
-
- if (bounds.right_out - bounds.right_in > 0)
- x_clear_region (window,
- get_builtin_face_cache_index (w, Vright_margin_face),
- bounds.right_in, ypos1,
- bounds.right_out - bounds.right_in, height);
-
- if (window_is_rightmost (w))
- x_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
- ypos1, FRAME_BORDER_WIDTH (f), height);
- }
- }
-
- /*****************************************************************************
- x_redraw_exposed_window
-
- Given a bounding box for an area that needs to be redrawn, determine
- what parts of what lines are contained within and re-output their
- contents.
- ****************************************************************************/
- static void
- x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
- {
- struct frame *f = XFRAME (w->frame);
- int line;
- int start_x, start_y, end_x, end_y;
- int orig_windows_structure_changed;
-
- display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
-
- if (!NILP (w->vchild))
- {
- x_redraw_exposed_windows (w->vchild, x, y, width, height);
- return;
- }
- else if (!NILP (w->hchild))
- {
- x_redraw_exposed_windows (w->hchild, x, y, width, height);
- return;
- }
-
- /* If the window doesn't intersect the exposed region, we're done here. */
- if (x > WINDOW_RIGHT (w) || (x + width) < WINDOW_LEFT (w)
- || y > WINDOW_BOTTOM (w) || (y + height) < WINDOW_TOP (w))
- {
- return;
- }
- else
- {
- start_x = max (WINDOW_LEFT (w), x);
- end_x = min (WINDOW_RIGHT (w), (x + width));
- start_y = max (WINDOW_TOP (w), y);
- end_y = min (WINDOW_BOTTOM (w), y + height);
-
- /* We do this to make sure that the 3D modelines get redrawn if
- they are in the exposed region. */
- orig_windows_structure_changed = f->windows_structure_changed;
- f->windows_structure_changed = 1;
- }
-
- if (window_needs_vertical_divider (w))
- {
- x_output_vertical_divider (w, 0);
- }
-
- for (line = 0; line < Dynarr_length (cdla); line++)
- {
- struct display_line *cdl = Dynarr_atp (cdla, line);
- int top_y = cdl->ypos - cdl->ascent;
- int bottom_y = cdl->ypos + cdl->descent;
-
- if (bottom_y >= start_y)
- {
- if (top_y > end_y)
- {
- if (line == 0)
- continue;
- else
- break;
- }
- else
- {
- output_display_line (w, 0, cdla, line, start_x, end_x);
- }
- }
- }
-
- f->windows_structure_changed = orig_windows_structure_changed;
-
- /* If there have never been any face cache_elements created, then this
- expose event doesn't actually have anything to do. */
- if (Dynarr_largest (w->face_cache_elements))
- redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
- }
-
- /*****************************************************************************
- x_redraw_exposed_windows
-
- For each window beneath the given window in the window hierarchy,
- ensure that it is redrawn if necessary after an Expose event.
- ****************************************************************************/
- static void
- x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
- int height)
- {
- for (; !NILP (window); window = XWINDOW (window)->next)
- x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
- }
-
- /*****************************************************************************
- x_redraw_exposed_area
-
- For each window on the given frame, ensure that any area in the
- Exposed area is redrawn.
- ****************************************************************************/
- void
- x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
- {
- /* If any window on the frame has had its face cache reset then the
- redisplay structures are effectively invalid. If we attempt to
- use them we'll blow up. We mark the frame as changed to ensure
- that redisplay will do a full update. This probably isn't
- necessary but it can't hurt. */
-
- /* #### We would rather put these off as well but there is currently
- no combination of flags which will force an unchanged toolbar to
- redraw anyhow. */
- x_redraw_exposed_toolbars (f, x, y, width, height);
-
- if (!f->window_face_cache_reset)
- {
- x_redraw_exposed_windows (f->root_window, x, y, width, height);
-
- XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
- }
- else
- MARK_FRAME_CHANGED (f);
- }
-
- /****************************************************************************
- x_clear_region
-
- Clear the area in the box defined by the given parameters using the
- given face.
- ****************************************************************************/
- static void
- x_clear_region (Lisp_Object locale, face_index findex, int x, int y,
- int width, int height)
- {
- struct window *w = 0;
- struct frame *f = 0;
- struct device *d;
- Lisp_Object background_pixmap;
-
- Display *dpy;
- Window x_win;
-
- if (WINDOWP (locale))
- {
- w = XWINDOW (locale);
- f = XFRAME (w->frame);
- }
- else if (FRAMEP (locale))
- {
- w = 0;
- f = XFRAME (locale);
- }
- else
- abort ();
-
- d = XDEVICE (f->device);
- dpy = DEVICE_X_DISPLAY (d);
- x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
-
- /* #### This function is going to have to be made cursor aware. */
- if (width && height)
- {
- int values_set = 0;
- GC gc;
-
- /* #### This isn't quite right for when this function is called
- from the toolbar code. */
- background_pixmap = Qunbound;
-
- /* Don't use a backing pixmap in the border area */
- if (x >= FRAME_LEFT_BORDER_END (f)
- && x < FRAME_RIGHT_BORDER_START (f)
- && y >= FRAME_TOP_BORDER_END (f)
- && y < FRAME_BOTTOM_BORDER_START (f))
- {
- Lisp_Object temp;
-
- if (w)
- {
- temp = FACE_CACHE_ELEMENT_BACKGROUND_PIXMAP (w, findex);
-
- if (IMAGE_INSTANCEP (temp)
- && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
- {
- /* #### maybe we could implement such that a string
- can be a background pixmap? */
- background_pixmap = temp;
- }
- }
- else
- {
- temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
-
- if (IMAGE_INSTANCEP (temp)
- && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
- {
- background_pixmap = temp;
- }
- }
-
- if (!UNBOUNDP (background_pixmap) &&
- XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
- {
- Lisp_Object fcolor, bcolor;
-
- if (w)
- {
- fcolor = FACE_CACHE_ELEMENT_FOREGROUND (w, findex);
- bcolor = FACE_CACHE_ELEMENT_BACKGROUND (w, findex);
- }
- else
- {
- fcolor = FACE_FOREGROUND (Vdefault_face, locale);
- bcolor = FACE_BACKGROUND (Vdefault_face, locale);
- }
-
- gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap,
- Qnil);
- values_set = 1;
- }
- else
- {
- Lisp_Object color;
-
- if (UNBOUNDP (background_pixmap))
- background_pixmap = Qnil;
-
- if (w)
- color = FACE_CACHE_ELEMENT_BACKGROUND (w, findex);
- else
- color = FACE_BACKGROUND (Vdefault_face, locale);
-
- gc = x_get_gc (d, Qnil, color, Qnil, background_pixmap,
- Qnil);
- values_set = 1;
- }
- }
-
- if (values_set)
- {
- XFillRectangle (dpy, x_win, gc, x, y, width, height);
- }
- else
- {
- XClearArea (dpy, x_win, x, y, width, height, False);
- }
- }
- }
-
- /*****************************************************************************
- x_output_eol_cursor
-
- Draw a cursor at the end of a line. The end-of-line cursor is
- narrower than the normal cursor.
- ****************************************************************************/
- static void
- x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos)
- {
- struct frame *f = XFRAME (w->frame);
- struct device *d = XDEVICE (f->device);
-
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
- GC gc;
- Pixel cursor_color;
- struct font_metric_info fm;
- int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS (d));
-
- int x = xpos;
- int y = dl->ypos - dl->ascent;
- int width = EOL_CURSOR_WIDTH;
- int height = dl->ascent + dl->descent - dl->clip;
- int cursor_height, cursor_y;
-
- XtVaGetValues (FRAME_X_TEXT_WIDGET (f), XtNcursorColor, &cursor_color, 0);
-
- gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil, Qnil);
-
- XClearArea (dpy, x_win, x, y, width, height, False);
-
- x_font_metric_info (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm);
- cursor_y = dl->ypos - fm.ascent;
- if (cursor_y < y)
- cursor_y = y;
- cursor_height = fm.height;
- if (cursor_y + cursor_height > y + height)
- cursor_height = y + height - cursor_y;
-
- if (focus)
- {
- if (NILP (Vbar_cursor))
- {
- XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
- }
- else
- {
- int bar_width = EQ (Vbar_cursor, Qt) ? 1 : 2;
-
- gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil,
- make_number (bar_width));
- XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
- x + bar_width - 1, cursor_y + cursor_height - 1);
- }
- }
- else if (NILP (Vbar_cursor))
- {
- XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
- cursor_height - 1);
- }
- }
-
- static void x_clear_frame_windows (Lisp_Object window);
-
- static void
- x_clear_frame_window (Lisp_Object window)
- {
- struct window *w = XWINDOW (window);
-
- if (!NILP (w->vchild))
- {
- x_clear_frame_windows (w->vchild);
- return;
- }
-
- if (!NILP (w->hchild))
- {
- x_clear_frame_windows (w->hchild);
- return;
- }
-
- x_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w));
- }
-
- static void
- x_clear_frame_windows (Lisp_Object window)
- {
- for (; !NILP (window); window = XWINDOW (window)->next)
- x_clear_frame_window (window);
- }
-
- static void
- x_clear_frame (struct frame *f)
- {
- struct device *d = XDEVICE (f->device);
- Display *dpy = DEVICE_X_DISPLAY (d);
- Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
- int x, y, width, height;
- Lisp_Object frame;
-
- x = FRAME_LEFT_BORDER_START (f);
- width = (FRAME_PIXWIDTH (f) - FRAME_LEFT_TOOLBAR_WIDTH (f) -
- FRAME_RIGHT_TOOLBAR_WIDTH (f));
- /* #### This adjustment by 1 should be being done in the macros.
- There is some small differences between when the menubar is on
- and off that we still need to deal with. */
- y = FRAME_TOP_BORDER_START (f) - 1;
- height = (FRAME_PIXHEIGHT (f) - FRAME_TOP_TOOLBAR_HEIGHT (f) -
- FRAME_BOTTOM_TOOLBAR_HEIGHT (f)) + 1;
-
- XClearArea (dpy, x_win, x, y, width, height, False);
-
- XSETFRAME (frame, f);
-
- if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
- || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
- || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
- {
- x_clear_frame_windows (f->root_window);
- }
-
- XFlush (DEVICE_X_DISPLAY (d));
- }
-
- /* briefly swap the foreground and background colors.
- */
-
- static int
- x_flash (struct device *d)
- {
- Display *dpy;
- Window w;
- XGCValues gcv;
- GC gc;
- XColor tmp_fcolor, tmp_bcolor;
- Lisp_Object tmp_pixel, frame;
- struct frame *f = device_selected_frame (d);
- Widget shell = FRAME_X_SHELL_WIDGET (f);
- Dimension width, height;
-
- XtVaGetValues (shell, XtNwidth, &width, XtNheight, &height, 0);
- XSETFRAME (frame, f);
-
- tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
- tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
- tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
- tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
-
- dpy = XtDisplay (shell);
- w = XtWindow (FRAME_X_TEXT_WIDGET (f));
- memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
- gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
- gcv.function = GXxor;
- gcv.graphics_exposures = False;
- gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
- (GCForeground | GCFunction | GCGraphicsExposures));
- XFillRectangle (dpy, w, gc, 0, 0, width, height);
- XSync (dpy, False);
-
- {
- int usecs = 100000;
- struct timeval tv;
- tv.tv_sec = usecs / 1000000L;
- tv.tv_usec = usecs % 1000000L;
- /* I'm sure someone is going to complain about this... */
- (void) select (0, 0, 0, 0, &tv);
- }
-
- XFillRectangle (dpy, w, gc, 0, 0, width, height);
- XSync (dpy, False);
-
- return 1;
- }
-
- /* Make audible bell. */
-
- static void
- x_ring_bell (struct device *d, int volume, int pitch, int duration)
- {
- Display *display = DEVICE_X_DISPLAY (d);
-
- if (volume < 0) volume = 0;
- else if (volume > 100) volume = 100;
- if (pitch < 0 && duration < 0)
- {
- XBell (display, (volume * 2) - 100);
- XFlush (display);
- }
- else
- {
- XKeyboardState state;
- XKeyboardControl ctl;
- XSync (display, 0);
- /* #### grab server? */
- XGetKeyboardControl (display, &state);
-
- ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
- ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
- XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
-
- XBell (display, (volume * 2) - 100);
-
- ctl.bell_pitch = state.bell_pitch;
- ctl.bell_duration = state.bell_duration;
- XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
-
- /* #### ungrab server? */
- XSync (display, 0);
- }
- }
-
-
- /************************************************************************/
- /* initialization */
- /************************************************************************/
-
- void
- device_type_create_redisplay_x (void)
- {
- /* redisplay methods */
- DEVICE_HAS_METHOD (x, text_width);
- DEVICE_HAS_METHOD (x, font_metric_info);
- DEVICE_HAS_METHOD (x, output_display_block);
- DEVICE_HAS_METHOD (x, divider_width);
- DEVICE_HAS_METHOD (x, divider_height);
- DEVICE_HAS_METHOD (x, eol_cursor_width);
- DEVICE_HAS_METHOD (x, output_vertical_divider);
- DEVICE_HAS_METHOD (x, clear_to_window_end);
- DEVICE_HAS_METHOD (x, clear_region);
- DEVICE_HAS_METHOD (x, clear_frame);
- DEVICE_HAS_METHOD (x, output_begin);
- DEVICE_HAS_METHOD (x, output_end);
- DEVICE_HAS_METHOD (x, flash);
- DEVICE_HAS_METHOD (x, ring_bell);
- }
-